/*
#[derive(Debug)]
struct Person{
  name:String,
  age:u8
}

impl Person {
  fn new(name: String, age:u8)->Self{
    Person{name, age}
  }
  fn display(self: &mut Person, age: u8){
    let Person{name, age}=&self; // &self == &&mut Person, 为什么&&mut Person能与Person类型进行匹配?
  }
}
*/

// 智能指针实现了Deref和Drop特征
// Deref: 可以让智能指针像引用那样工作,码农就可以写出同时支持智能指针和引用的代码.如: *T
// Drop: 允许你指定智能指针超出作用域后自动执行的代码

pub fn learn_deref() {
    _learn_deref_useful();
    _learn_smart_point();
    _learn_my_smart_point();
    _learn_implicit_convert();
    _learn_implicit_convert_until();
}

fn _learn_deref_useful() {
    let x = 5;
    let y = &x; // y是一个常规引用,包含了5所在的内存地址
    assert_eq!(5, x);
    assert_eq!(5, *y); // 通过解引用 *y, 得到值5

    // assert_eq!(5, y); // can't compare `{integer}` with `&{integer}`
}

// 智能指针的解引用
fn _learn_smart_point() {
    let x = Box::new(1);
    let sum = *x + 1; // 智能指针x被 * 解引用为i32类型的值1,然后再求和.
    assert_eq!(2, sum);
}

// 定义自己的智能指针
struct MyBox<T>(T);
impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
// 为智能指针实现Deref特征
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
    type Target = T;
    // &self是self:&Self的简写
    fn deref(&self) -> &Self::Target {
        &self.0 // 返回单位元组的第一个引用: &self.0 == &(self.0)
    }
}
fn _learn_my_smart_point() {
    let y = MyBox::new(5);
    assert_eq!(5, *y);
}

// * 背后的原理
// 对智能指针解引用,其实是调用了方法: *(y.deref())
// 首先调用deref方法, 返回值的常规引用, 然后通过 * 对常规引用进行解引用, 最终获得目标值
// 受所有权系统的影响: 如果deref方法直接返回值, 就意味着值的所有权被转移给调用者.
// 一般不希望仅仅是 *T 一下, 就拿走了智能指针中的值(及其所有权)
// 注意, * 不会无限递归替换, 从 *y 到 *(y.deref()) 只会发生一次, 而不会永续替换下去
// 成为: *((y.deref()).deref()) 这样的怪物.

// 函数和方法中的隐式Deref转换
// 如果一个类型实现了Deref,则它的引用在传递给函数或方法时,会根据参数签名来决定是否进行隐式的Deref转换.
fn _learn_implicit_convert(){
  let s=String::from("hello implicit"); // String类型实现了Deref,可以转换为&str
  _display(&s); //&s 是一个 &String类型, 传给_display函数时,自动通过Deref转换成了&str
  // 必须使用&s的方式来触发Deref(仅引用类型的实参才会触发自动解引用)
}

fn _display(s:&str){
  println!("{}", s);
}

// 连续的隐式Deref转换,直到找到合适的形式为止
fn _learn_implicit_convert_until(){
  let s=MyBox::new(String::from("hello until"));
  // 第一步,Mybox被Deref为String,不满足_display函数参数的要求,
  // 编译器发现String可以Deref为&str,满足_display
  _display(&s);
  // 如果不提供这种连续隐式转换,则:
  // *s==String
  _display(&(*s));
  _display(&(*s)[..]);

  // 在方法,赋值中自动应用Deref的例子:
  let s1:&str=&s; 
  //let s1=&s; // 如果不指定绑定的变量的类型,就不会隐式转换,编译器推导出的类型就是&Mybox<String>
  // 即 编译器通过两次Deref得到&str(赋值操作需要手动解引用).

  let s2:String=s.to_string(); // 这里如果不指定类型,推导的类型也是String
  // 因为Mybox上没有to_string方法,能调用to_string,是因为编译器对MyBox应用了Deref的结果
  // (方法调用会自动解引用)
}

// Deref规则总结:
// 一个类型为T的对象foo,如果T:Deref<Target=U>,那么foo的引用&foo在应用的时候自动转换为&U

// 引用归一化
// 1,把智能指针(如库中定义的:Box,Rc,Arc,Cow等)从结构体脱壳为内部的引用类型,即转为结构体内部的&v
// 2,把多重&, 例如: &&&&&&v, 归一成 &v

/* 标准库中的源码:
impl<T: ?Sized> Deref for &T{
  type Target = T;
  fn deref(&self) -> &T {
    *self
  }
}
*/

// 三种Deref转换
// 当T: Deref<Target=U>, 可以将 &T 转换成 &U, 即上述各种例子
// 当T: DerefMut<Target=U>, 可以将 &mut T 转换成 &mut U
// 当T: Deref<Target=U>, 可以将 &mut T 转换成 &U

// 一些DerefMut的例子:
struct MyBox2<T> {
  v: T,
}
impl<T> MyBox2<T> {
  fn new(x:T)->MyBox2<T> {
    MyBox2{v:x}
  }
}

impl<T> Deref for MyBox2<T> {
  type Target=T;
  fn deref(&self)->&Self::Target{
    &self.v
  }
}

use std::ops::DerefMut;

// 注意1:要实现DerefMut,必须先实现Deref. 因为 pub trait DerefMut: Deref
impl<T> DerefMut for MyBox2<T> {
  fn deref_mut(&mut self)->&mut Self::Target{
    &mut self.v
  }
}
// 注意2: T: DerefMut<Target=U> 解读: 将&mut T类型通过DerefMut特征的方法转换为
// &mut U类型, 就是将&mut MyBox2<String>转换为 &mut String

fn _learn_deref_mut(){
  let mut s = MyBox2::new(String::from("hello"));
  _display_mut(&mut s)
}

fn _display_mut(s: &mut String){
  s.push_str("world");
  println!("{}", s);
}
// 注意3: Rust可以把可变引用隐式转换为不可变引用,但反之则不行.
// 从所有权和借用规则的角度考虑:当你拥有一个可变的引用,那该引用肯定是对应数据的唯一借用.
// 那么此时将可变引用转换为不可变引用并不会破坏借用规则;但是如果你拥有一个不可变引用,
// 同时可能还存在其他几个不可变的引用,此时将其中一个不可变引用转换为可变引用,就变成了
// 可变引用与不可变引用共存,就破坏了借用规则

// 原则上类说,只应该为自定义智能指针实现Deref.